package com.wys.spring.mybatisplus.service;

import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.LambdaUtils;
import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import com.baomidou.mybatisplus.core.toolkit.support.SFunction;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.wys.api.common.R;
import com.wys.api.exception.BizException;
import io.swagger.annotations.ApiModelProperty;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.reflect.FieldUtils;
import org.apache.ibatis.reflection.property.PropertyNamer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.dao.DataAccessException;
import org.springframework.transaction.annotation.Transactional;

import javax.validation.constraints.NotNull;
import java.io.Serializable;
import java.lang.reflect.Field;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

public abstract class BaseService<T, M extends BaseMapper<T>> extends ServiceImpl<M, T> {

    private static final Logger logger = LoggerFactory.getLogger(BaseService.class);


    /**
     * 根据条件查询
     *
     * @param lambdaQueryWrapper lambda表达式
     * @return List
     */
    public List<T> queryList(LambdaQueryWrapper<T> lambdaQueryWrapper) {
        try {
            return this.list(lambdaQueryWrapper);
        } catch (Exception e) {
            logger.error("根据条件查询业务异常:", e);
            throw new BizException("查询业务异常");
        }
    }


    /**
     * 分页查询
     *
     * @param lambdaQueryWrapper lamb表达
     * @param page               分页实体类
     * @return
     */
    public IPage<T> queryPage(LambdaQueryWrapper<T> lambdaQueryWrapper, IPage<T> page) {
        try {
            return this.page(page, lambdaQueryWrapper);
        } catch (Exception e) {
            logger.error("分页查询异常:", e);
            throw new BizException("分页查询业务异常");
        }
    }

    public R<IPage<T>> queryPageByR(LambdaQueryWrapper<T> lambdaQueryWrapper, IPage<T> page) {
        return R.ok(queryPage(lambdaQueryWrapper, page));
    }


    public long countV(LambdaQueryWrapper<T> lambdaQueryWrapper) {
        try {
            return this.count(lambdaQueryWrapper);
        } catch (Exception e) {
            logger.error("根据条件获取返回数据行数异常:", e);
            throw new BizException("根据条件获取返回数据行数异常");
        }
    }


    public T queryOne(LambdaQueryWrapper<T> lambdaQueryWrapper) {
        try {
            lambdaQueryWrapper.last("limit 1");
            return this.getOne(lambdaQueryWrapper);
        } catch (Exception e) {
            logger.error("获取单条数据集异常:", e);
            throw new BizException("获取单个查询结果异常");
        }
    }

    @Transactional(rollbackFor = {Exception.class, BizException.class})
    public R addOne(T t) {
        try {
            if (!this.save(t)) {
                throw new BizException("数据保存失败");
            }
            return R.ok("数据保存成功", t);
        } catch (DataAccessException | BizException n) {
            throw n;
        } catch (Exception e) {
            logger.error("数据保存异常:", e);
            throw new BizException("保存数据业务异常");
        }
    }

    public void addAll(Collection<T> list) {
        try {
            this.saveBatch(list, list.size());
        } catch (DataAccessException | BizException n) {
            throw n;
        } catch (Exception e) {
            logger.error("批量插入数据业务异常:", e);
            throw new BizException("批量保存数据业务异常");
        }
    }

    @SafeVarargs
    public final void queryByAdd(LambdaQueryWrapper<T> lambdaQueryWrapper, Collection<T> collection, SFunction<T, ?>... field) {
        try {
            checkFieldValue(lambdaQueryWrapper, field);
            this.addAll(collection);
        } catch (DataAccessException | BizException n) {
            throw n;
        } catch (Exception e) {
            logger.error("根据查询提交保存数据业务异常:", e);
            throw new BizException("根据条件保存数据业务异常");
        }
    }

    /**
     * 根据条件判断指定字段的值是否在数据库中已经存在
     *
     * @param lambdaQueryWrapper 查询条件
     * @param field              指定的字段
     */
    @SafeVarargs
    public final void checkFieldValue(LambdaQueryWrapper<T> lambdaQueryWrapper, @NotNull SFunction<T, ?>... field) {
        List<T> list = this.queryList(lambdaQueryWrapper);
        List<String> fieldNames = Arrays.stream(field).map(s -> PropertyNamer.methodToProperty(LambdaUtils.extract(s).getImplMethodName())).collect(Collectors.toList());
        Map<String, Object> map = new HashMap<>();
        if (com.baomidou.mybatisplus.core.toolkit.ObjectUtils.isNotEmpty(list)) {
            list.forEach(l -> {
                List<Field> fields = FieldUtils.getAllFieldsList(l.getClass());
                fields.forEach(f -> {
                    f.setAccessible(true);
                    if (fieldNames.contains(f.getName())){
                        ApiModelProperty apiModelProperty = f.getAnnotation(ApiModelProperty.class);
                        if (StringUtils.isNotBlank(apiModelProperty.value())) {
                            try {
                                map.put(apiModelProperty.value(), f.get(l));
                            } catch (IllegalAccessException e) {
                                throw new RuntimeException(e);
                            }
                        }
                    }
                });
            });
            if (ObjectUtils.isNotEmpty(map)) {
                throw new BizException(map.toString().replace("{", "").replace("}", "").replace(","," 或 ").concat(" 在数据库中已存在!!"));
            }
        }
    }


    /**
     * 根据条件更新数据
     *
     * @param t
     * @param lambdaUpdateWrapper 查询更新条件
     */
    @Transactional(rollbackFor = {Exception.class, BizException.class})
    public R updateByOne(T t, Wrapper<T> lambdaUpdateWrapper) {
        try {
            this.update(t, lambdaUpdateWrapper);
            return R.ok("数据更新成功");
        } catch (DataAccessException | BizException n) {
            throw n;
        } catch (Exception e) {
            logger.error("数据更新业务异常:", e);
            throw new BizException("更新数据业务异常");
        }
    }

    public R updateByIdForOne(T t) {
        try {
            return this.updateById(t) ? R.ok("数据更新成功", t) : R.fail("数据更新失败", t);
        } catch (Exception e) {
            logger.error("数据更新异常:", e);
            return R.ok("数据更新失败");
        }
    }


    /**
     * @param t                  实体对象
     * @param lambdaQueryWrapper 查询条件
     */
    public void addOrUpdate(T t, LambdaQueryWrapper<T> lambdaQueryWrapper) {
        try {
            List<T> list = this.queryList(lambdaQueryWrapper);
            if (ObjectUtils.isNotEmpty(list)) {
                this.updateById(t);
            } else {
                addOne(t);
            }
        } catch (DataAccessException | BizException n) {
            throw n;
        } catch (Exception e) {
            logger.error("更新或者保存数据异常:", e);
            throw new BizException("数据更新或保存业务异常");
        }
    }


    /**
     * 支持假删除
     *
     * @param id
     * @return
     */
    public R delById(Serializable id) {
        try {
            boolean b = this.removeById(id, true);
            return R.ok(b ? "删除成功" : "删除失败", b);
        } catch (Exception e) {
            logger.error("根据id删除数据异常:", e);
            return R.fail("删除数据失败");
        }
    }

    public R getDetailById(Serializable id) {
        try {
            return R.ok(this.getById(id));
        } catch (Exception e) {
            logger.error("根据id获取数据详情接口业务异常:", e);
            return R.fail("根据id获取数据详情业务异常");
        }
    }


}
